Performane evaluation of open-source 5G Core networks

General Workload Chacterisation

Virtual Network Functions (VNFs) are network functions that run on virtualised platforms. Virtualisation allows NFs to run on commercial off-the-shelf infrastructure. There are different virtualisation approaches, the most common being hypervisor virtualisation and OS-level virtualisation [? ], [? ]. Regardless of the manner of virtualisation employed, in most cases, a VNF is a piece of software that runs on top of the Linux kernel, and this degrades its performance compared to the hardware NF [? ]

To gain a better understanding of how virtualisation affects performance and how the software architecture of VNFs affects the performance of the 5G core networks, it is necessary to dive deeper into the underlying operations of the Linux kernel. A standard Linux system is based on the monolithic kernel architecture, which divides the system into two main components: kernel-space and user-space, which operate at different privilege levels. The kernel-space is responsible for managing the hardware and software components of the system and accounts for independent operations of programs. The user-space contains and executes user-defined programs and data. These two spaces are kept separate from each other, and communication between them is only possible through secure system calls. This concept allows the Linux kernel to abstract away the complexities of interacting directly with the hardware, which requires specialised communication

The system calls provide abstract APIs for various functionalities, including process management, memory management, file systems, device drivers, and networking. The kernel manages and executes these system calls by interfacing with the software or hardware support modules, as described and illustrated in [? ]. Of importance to the scope of this study is process manage

Syscalls ascross the system
Processes making syscalls
epoll/poll/select
read/write
recv, recvfrom, recvmsg, recvmmsg. recvfrom(), recvmsg() and recvmmsg()
send, sendto, sendmsg, sendmmsg
nanosleep/clock_nanosleep
futex
sched_yield
free5GC: by process analysis
Open5GS: by process analysis
OAI: by process analysis

Syscalls across the system.

Analysing system calls (syscalls) across the system helps in categorising the workload of the system. This information is valuable in identifying the hardware resources that require optimisation, such as installing an accelerated network card interface (NIC) or a cryptographic accelerator




Syscalls across the system.



Processes making syscalls

The information about the processes that make system calls provides valuable insights into the most active processes during the registration procedure. By observing the changes in latency and frequency of the system calls made by a process as the number of UEs increases, we can identify processes that have a high probability of becoming bottlenecks. The information can be used to make several mitigation decisions, such as allocating more resources or dedicated resources to a given process or Network Function (NF), optimising the usage by the NF or process, and examining the configuration of the process, among other things.






Process free5gc


Process oai


Process open5gs


epoll/poll/select


The system calls epoll/poll/select implement I/O multiplexing, which enables the simultaneous monitoring of multiple input and output sources in a single operation. These system calls are based on the Linux design principle, which considers everything as a file and operates by monitoring files to determine if they are ready for the requested operation. The main advantage of multiplexing I/O operations is that it avoids blocking read and write where a process will wait for data while on the CPU. Instead, one waits for the multiplexing I/O system calls to determine which files are ready for read or write.



















































read/write


The read() system call is used to retrieve data from a file stored in the file system, while the write() system call is used to write data from a buffer to a file. Both system calls take into account the "count", which represents the number of bytes to read or write. Upon successful execution, these system calls return the number of bytes that were successfully read or written. By default, these system calls are blocking but can be changed to non-blocking using the fnctl system call. Blocking is a problem for programs that should operate concurrently, since blocked processes are suspended. There are two different, complementary ways to solve this problem. They are nonblocking mode and I/O multiplexing system calls, such as select and epoll. The architectural decision to use a combination of multiplexing I/O operations and non-blocking system calls offers advantages depending on the use cases. Some scenarios where this approach is beneficial include situations where small buffers would result in repeated system calls, when the system is dedicated to one function, or when multiple I/O system calls return an error.
























recv, recvfrom, recvmsg, recvmmsg. recvfrom(), recvmsg() and recvmmsg()


These are all system calls used to receive messages from a socket. They can be used to receive data on a socket, whether or not it is connection-orientated. These system calls are blocking calls; if no messages are available at the socket, the receive calls wait for a message to arrive. If the socket is set to non-blocking, then the value -1 is returned and errno is set to EAGAIN or EWOULDBLOCK. Passing the flag MSG_DONTWAIT to the system call enables non-blocking operation. This provides behaviour similar to setting O_NONBLOCK with fcntl except MSG_DONTWAIT is per operation. The recv() call is normally used only on a connected socket and is identical to recvfrom() with a nil from parameter. recv(), recvfrom() and recvmsg() calls return the number of bytes received, or -1 if an error occurred. For connected sockets whose remote peer was shut down, 0 is returned when no more data is available. The recvmmsg() call returns the number of messages received, or -1 if an error occurred
























send, sendto, sendmsg, sendmmsg


The send() call may only be used when the socket is in a connected state (so that the intended recipient is known). The send() is similar to write() with the difference of flags. The sendto and sendmsg work on both connected and unconnected sockets. The sendmsg() call also allows sending ancillary data (also known as control information). The sendmmsg() system call is an extension of sendmsg that allows the caller to transmit multiple messages on a socket using a single system call. The approaches to optimise the send(s) system calls are similar to the discussed approaches for the recv(s) system calls. These include I/O multiplexing, using the system calls in non-blocking mode, and sending multiple messages in a single system call where possible
























nanosleep/clock_nanosleep


The nanosleep and clock_nanosleep system calls are used to allow the calling thread to sleep for a specific interval with nanosecond precision. The clock_nanosleep differs from nanosleep in two ways. Firstly, it allows the caller to select the clock against which the sleep interval is to be measured. Secondly, it enables the specification of the sleep interval as either an absolute or a relative value. Using an absolute timer is useful to prevent timer drift issues mentioned about nanosleep.
























futex


The futex() system call offers a mechanism to wait until a specific condition becomes true. It is typically used as a blocking construct in the context of shared-memory synchronisation. Additionally, futex() operations can be employed to wake up processes or threads that are waiting for a particular condition. The main design goal of futex is to manage the mutex keys in the user space to avoid context switches when handling mutex in kernel space. In the futex design, the kernel is involved only when a thread needs to sleep or the system needs to wake up another thread. Essentially, the futex system call can be described as providing a kernel side wait queue indexed by a user space address, allowing threads to be added or removed from user space. A high frequency of calls to the futex system may indicate a high degree of concurrent access to shared resources or data structures by multiple threads or processes.















sched_yield


The sched_yield system call is used by a thread to allow other threads a chance to run, and the calling thread relinquishes the CPU. Strategic calls to sched_yield() can improve performance by giving other threads or processes an opportunity to run when (heavily) contended resources, such as mutexes, have been released by the caller. The authors of were able to improve the throughput of their system by employing the sched_yield system call after a process processes each batch of packets before calling the poll. On the other hand, sched_yield can result in unnecessary context switches, which will degrade system performance if not used appropriately. The latter is mainly true in generic Linux systems, as the scheduler is responsible for deciding which process runs. In most cases, when a process yields, the scheduler may perceive it as a higher priority and still put it back into execution, where it yields again in a loop. This behaviour is mainly due to the algorithm and logic used by Linux’s default scheduler to determine the process with the higher prior















free5GC


This section focuses on the free5GC core network and presents results per process. This helps to identify the processes that are responsible for the aggregated usage and frequency. This information can be useful for developers, who can use it to focus their optimisation efforts on the most critical processes. It can also be used to identify processes that are potential bottlenecks.






































































































































































































Open5GS


This section focuses on the OAI core network and presents results per process. This helps to identify which processes are responsible for the aggregated usage and frequency, and informs developers which processes to focus on. It can also help to identify processes that may be potential bottlenecks.














































































































































































































































































OAI


This analysis is complementary to the results presented in the main body of the paper, which showed the aggregated usage and frequency of system calls across the core network. By identifying the processes that are responsible for the highest system call usage and frequency, we can help developers to focus their efforts on optimising these processes and identifying potential bottlenecks.